#ifndef VECTOR3_HEADER_VIZMF_PROJECT
#define VECTOR3_HEADER_VIZMF_PROJECT

#include <boost/array.hpp>
#include <ostream>
#include <cmath>	// for std::sqrt //!! not sure

class Vector3
{
public:
  typedef double float_type; // float is too short to store coordinates

  Vector3(float_type a = 0.0, float_type b = 0.0, float_type c = 0.0)
  {
    x_[0] = a, x_[1] = b; x_[2] = c;
  }
  Vector3(float_type v[3])
  {
    x_[0] = v[0];
    x_[1] = v[1];
    x_[2] = v[2];
  }

  float_type length() const { return std::sqrt(x_[0]*x_[0] + x_[1]*x_[1] + x_[2]*x_[2] ); }
  const Vector3& normalize() {
    float_type n = length(); n = float_type(1.0) / (n ? n : 1.0);
    x_[0] *= n; x_[1] *= n; x_[2] *= n;
    return *this;
  }

  float_type& x() { return x_[0]; }
  float_type& y() { return x_[1]; }
  float_type& z() { return x_[2]; }
  const float_type& x() const { return x_[0]; }
  const float_type& y() const { return x_[1]; }
  const float_type& z() const { return x_[2]; }

  const float_type& operator [] (int i) const { return x_[i]; }
  float_type& operator [] (int i) { return x_[i]; }

  const float_type* vertex() const {return x_; }

  float_type dot(const Vector3& v) const { return x_[0]*v.x_[0] + x_[1]*v.x_[1] + x_[2]*v.x_[2]; }
  Vector3 prod(const Vector3& v) const {
    return Vector3(
      x_[1]*v.x_[2] - v.x_[1]*x_[2], x_[2]*v.x_[0] - v.x_[2]*x_[0], x_[0]*v.x_[1] - v.x_[0]*x_[1]
    );
  }
  bool operator ==(const Vector3& other) const
  {
    return x_[0] == other.x_[0] && x_[1] == other.x_[1] && x_[2] == other.x_[2];
  }
  Vector3 operator + (const Vector3& other) const
  {
    return Vector3(x_[0] + other.x_[0], x_[1] + other.x_[1], x_[2] + other.x_[2]);
  }
  Vector3 operator - () const
  {
    return Vector3(-x_[0], -x_[1], -x_[2]);
  }
  Vector3 operator - (const Vector3& other) const
  {
    return *this + (-other);
  }
  Vector3 operator += (const Vector3& other)
  {
    return *this = *this + other;
  }
  Vector3 operator -= (const Vector3& other)
  {
    return *this = *this - other;
  }
  Vector3 operator * (const float_type& a) const
  {
    return Vector3( a * x_[0], a * x_[1], a * x_[2]);
  }
  Vector3 operator / (const float_type& a) const
  {
    return Vector3( x_[0] / a, x_[1] / a, x_[2] / a);
  }
  Vector3 operator *= (const float_type& other)
  {
    return *this = *this * other;
  }
  Vector3 operator /= (const float_type& other)
  {
    return *this = *this / other;
  }

private:
  float_type x_[3];
};

inline Vector3 operator * (const double& a, const Vector3& vec)
{
  return vec * a;
}

inline std::ostream& operator << (std::ostream& strm, const Vector3& vec)
{
  return strm << "(" << vec[0] << ", " << vec[1] << ", " << vec[2] << ")";
}

#include <QDebug>
inline QDebug& operator << (QDebug& strm, const Vector3& vec)
{
  return strm << "(" << vec[0] << ", " << vec[1] << ", " << vec[2] << ")";
}

///////////////////////////////////////////////////////////////////////
// alternative vector class using boost::array, almost standard
// class
template<typename Real, size_t nDim = 3, typename Base=boost::array<Real,nDim> >
class Point3T
    : public Base
{
    typedef typename Base::value_type coord_type;
public:
    enum {kX = 0, kY = 1, kZ = 2};
    ///////////////////////////////////////////////////////////////////////
    // accessor functions:
    coord_type&       x()       { return Base::operator[](kX); }
    coord_type&       y()       { return Base::operator[](kY); }
    coord_type&       z()       { return Base::operator[](kZ); }
    const coord_type& x() const { return Base::operator[](kX); }
    const coord_type& y() const { return Base::operator[](kY); }
    const coord_type& z() const { return Base::operator[](kZ); }

};

typedef Point3T<double> DPoint3;
typedef Point3T<float > FPoint3;

#endif // VECTOR3_HEADER_VIZMF_PROJECT
